#include "transaction.hpp"

using etcdserverpb::Compare;
using etcdserverpb::RangeRequest;

namespace etcdv3 {

Transaction::Transaction() {
}

Transaction::Transaction(const std::string& key) : key(key) {
}

void Transaction::init_compare(Compare::CompareResult result, Compare::CompareTarget target) {
    auto compare = txn_request.add_compare();
    if (compare != nullptr) {
        compare->set_result(result);
        compare->set_target(target);
        compare->set_key(key);
        compare->set_version(0);
    }
}

void Transaction::init_compare(const std::string& old_value, Compare::CompareResult result, Compare::CompareTarget target) {
    auto compare = txn_request.add_compare();
    if (compare != nullptr) {
        compare->set_result(result);
        compare->set_target(target);
        compare->set_key(key);
        compare->set_value(old_value);
    }
}

void Transaction::init_compare(int old_index, Compare::CompareResult result, Compare::CompareTarget target) {
    auto compare = txn_request.add_compare();
    if (compare != nullptr) {
        compare->set_result(result);
        compare->set_target(target);
        compare->set_key(key);
        compare->set_mod_revision(old_index);
    }
}

// get key on failure
void Transaction::setup_basic_failure_operation(std::string const& key) {
    auto req_failure = txn_request.add_failure();
    if (req_failure != nullptr) {
        auto get_req = req_failure->mutable_request_range();
        if (get_req != nullptr) {
            get_req->set_key(key);
        }
    }
}

// get key on failure, get key before put, modify and then get updated key
void Transaction::setup_set_failure_operation(std::string const& key, std::string const& value, int64_t leaseid) {
    auto req_failure = txn_request.add_failure();
    if (req_failure != nullptr) {
        auto put_req = req_failure->mutable_request_put();
        if (put_req != nullptr) {
            put_req->set_key(key);
            put_req->set_value(value);
            put_req->set_prev_kv(true);
            put_req->set_lease(leaseid);
        }
    }

    req_failure = txn_request.add_failure();
    if (req_failure != nullptr) {
        auto get_req = req_failure->mutable_request_range();
        if (get_req != nullptr) {
            get_req->set_key(key);
        }
    }
}

// get key, delete
void Transaction::setup_delete_failure_operation(std::string const& key, std::string const& range_end, bool recursive) {
    auto req_failure = txn_request.add_failure();
    if (req_failure != nullptr) {
        auto get_req = req_failure->mutable_request_range();
        if (get_req != nullptr) {
            get_req->set_key(key);
            if (recursive) {
                get_req->set_range_end(range_end);
                get_req->set_sort_target(RangeRequest::SortTarget::RangeRequest_SortTarget_KEY);
                get_req->set_sort_order(RangeRequest::SortOrder::RangeRequest_SortOrder_ASCEND);
            }
        }
    }

    req_failure = txn_request.add_failure();
    if (req_failure != nullptr) {
        auto del_req = req_failure->mutable_request_delete_range();
        if (del_req != nullptr) {
            del_req->set_key(key);
            if (recursive) {
                del_req->set_range_end(range_end);
            }
        }
    }
}

// add key and then get new value of key
void Transaction::setup_basic_create_sequence(std::string const& key, std::string const& value, int64_t leaseid) {
    auto req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto put_req = req_success->mutable_request_put();
        if (put_req != nullptr) {
            put_req->set_key(key);
            put_req->set_value(value);
            put_req->set_prev_kv(true);
            put_req->set_lease(leaseid);
        }
    }

    req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto get_req = req_success->mutable_request_range();
        if (get_req != nullptr) {
            get_req->set_key(key);
        }
    }
}

// get key value then modify and get new value
void Transaction::setup_compare_and_swap_sequence(std::string const& value, int64_t leaseid) {
    auto req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto put_req = req_success->mutable_request_put();
        if (put_req != nullptr) {
            put_req->set_key(key);
            put_req->set_value(value);
            put_req->set_prev_kv(true);
            put_req->set_lease(leaseid);
        }
    }

    req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto get_req = req_success->mutable_request_range();
        if (get_req != nullptr) {
            get_req->set_key(key);
        }
    }
}

// get key, delete
void Transaction::setup_delete_sequence(std::string const& key, std::string const& range_end, bool recursive) {
    auto req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto del_req = req_success->mutable_request_delete_range();
        if (del_req != nullptr) {
            del_req->set_key(key);
            del_req->set_prev_kv(true);
            if (recursive) {
                del_req->set_range_end(range_end);
            }
        }
    }
}

void Transaction::setup_compare_and_delete_operation(std::string const& key) {
    auto req_success = txn_request.add_success();
    if (req_success != nullptr) {
        auto del_req = req_success->mutable_request_delete_range();
        if (del_req != nullptr) {
            del_req->set_key(key);
            del_req->set_prev_kv(true);
        }
    }
}

Transaction::~Transaction() {
}

}